﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Net;
using System.Text;
using SharePointClient.SPWebService.Copy;
//using System.Web.Services.Protocols;

namespace SharePointClient
{
    /// <summary>
    /// WSSBasisklasse
    /// </summary>
    public abstract class WSSBase
    {

        protected Connection myConnection=null;
        private Uri url;
        private XmlDocument xdoc=new XmlDocument();
        private Guid guid;
        private DateTime loaded=DateTime.MinValue;
        
        /// <summary>
        /// NeedRefresh returns true if Metadata is not up to date
        /// </summary>
        public virtual bool NeedRefresh
        {
            get { return loaded==DateTime.MinValue; }
            set { if (!value) loaded = DateTime.Now; }
        }
        /// <summary>
        /// Returns  if any Data has been loaded into Structure
        /// </summary>
        public bool HasNoData
        {
            get { return loaded == DateTime.MinValue; }
            protected set { if (value) loaded = DateTime.MinValue; }
        }
        /// <summary>
        /// Refresh is used to Load or Reload Data from WSS
        /// </summary>
        /// <remarks>Please call base.Refresh() at end of overwritten function for marking structure as Refreshed</remarks>
        public abstract void Refresh();
        /// <summary>
        /// Returns the CredentialsCache
        /// </summary>
        public ICredentials Credentials
        {
            get { return myConnection.Credentials; }
        }
        /// <summary>
        /// Refreshes data with new Login-Information
        /// </summary>
        /// <param name="authtype">"Basic" or "NTLM"</param>
        /// <param name="username">Your Username</param>
        /// <param name="password">Your Password</param>
        /// <param name="domain">Your Windows-Domain</param>
        /// <remarks>Use the base.Login at end of function to add Data to CredentialCache</remarks>
        public virtual void Login(string authtype, string username, string password, string domain)
        {
            if (!(myConnection.Credentials is CredentialCache)) myConnection.Credentials = new CredentialCache();
            ((CredentialCache)myConnection.Credentials).Remove(url, authtype);
            ((CredentialCache)myConnection.Credentials).Add(url, authtype, new NetworkCredential(username, password, domain));
        }

        /// <summary>
        /// Returns the path from the server-url
        /// </summary>
        /// 
        public string CurrentPath
        {
            get { return url.AbsolutePath;  }
        }
        /// <summary>
        /// Returns full Uri
        /// </summary>
        public Uri Uri
        {
            get { if (this.url.ToString().EndsWith("/")) return this.url; else return new Uri(this.url.ToString() + "/"); }
        }
       
        /// <summary>
        /// Returns Server-Address without path
        /// </summary>
        public Uri Server
        {
            get { return new Uri(url.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped)); }
        }
        /// <summary>
        /// Creates the Base-Class
        /// </summary>
        /// <param name="url"></param>
        public WSSBase(Connection sp,Uri url)
        {
           
            this.url = new Uri(url.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped));
            this.myConnection = sp;
        }

        /// <summary>
        /// Metadata should hold all significant informations of the instance-Type
        /// </summary>
        public XmlDocument MetaData
        {
            get { return xdoc; }
            set { xdoc = value; NeedRefresh = false; }
        }
        /// <summary>
        /// MetadataElement can create an XmlDocument from an XmlNode
        /// </summary>
        public XmlNode MetaDataElement
        {
            get { return xdoc.DocumentElement; }
            set
            {
                xdoc = new XmlDocument();
                XmlNamespaceManager n = new XmlNamespaceManager(xdoc.NameTable);
                n.AddNamespace("wss", value.NamespaceURI);
                n.AddNamespace(String.Empty, value.NamespaceURI);
                xdoc.LoadXml(value.OuterXml);
                NeedRefresh = false;
            }
        }
        
        /// <summary>
        /// Guid should hold the unique Identifier from the WSS for the particular instance. Please fill if existent.
        /// Future use for central caching is possible
        /// </summary>
        public Guid Guid
        {
            get { return guid; }
            protected set 
            { 
                guid = value;
                //if (!cache.ContainsKey(guid)) cache.Add(guid, this);
            }
        }


        public static XmlNodeList Select(XmlNode node, string xpath)
        {
            XmlNamespaceManager nm = new XmlNamespaceManager(new XmlDocument().NameTable);
            foreach (XmlAttribute a in node.Attributes)
                if (a.Name.StartsWith("xmlns:")) nm.AddNamespace(a.Name.Substring(6), a.Value);
            nm.AddNamespace("wss", "http://schemas.microsoft.com/sharepoint/soap/");
            return node.SelectNodes(xpath, nm);
        }
        public XmlNodeList Select(string xpath)
        {
            XmlNodeList nodes;
            XmlNamespaceManager nm = new XmlNamespaceManager(xdoc.NameTable);
            foreach (XmlAttribute a in MetaDataElement.Attributes)
                if (a.Name.Length >= 6 && a.Name.Substring(0, 6) == "xmlns:") nm.AddNamespace(a.Name.Substring(6), a.Value);
                else if (a.Name == "xmlns") nm.AddNamespace("wss", a.Value);
            
            nodes= MetaDataElement.SelectNodes(xpath, nm);
            return nodes;
        }
        public string SelectItem(string xpath)
        {
            XmlNodeList search = Select(xpath);
            if (search.Count == 1) return search[0].Value;
            else return "";
        }
        public static DateTime DateTimeFromWSS(string dateTimeString)
        {
            return new DateTime(
                Convert.ToInt32(dateTimeString.Substring(0, 4)),
                Convert.ToInt32(dateTimeString.Substring(4, 2)),
                Convert.ToInt32(dateTimeString.Substring(6, 2)),
                Convert.ToInt32(dateTimeString.Substring(9, 2)),
                Convert.ToInt32(dateTimeString.Substring(12, 2)),
                Convert.ToInt32(dateTimeString.Substring(15, 2)), DateTimeKind.Utc).ToLocalTime();
            
           
        }

        /// <summary>
        /// Write Metadata of object to file
        /// </summary>
        /// <param name="filename">filename for output</param>
        public void WriteXml(string filename)
        {
            FileStream f = new FileStream(filename, FileMode.CreateNew);
            MetaData.WriteTo(XmlWriter.Create(f));
            f.Close();
        }
        public override string ToString()
        {
            return "\"" + Uri.ToString()  + "\" (" + this.GetType().FullName + ")";
        }



    }
}
